package com.rockcent.wechat.controller;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rockcent.common.common.JsonResult;
import com.rockcent.common.common.RestDoing;
import com.rockcent.common.common.WebDoing1;
import com.rockcent.common.controller.BaseController;
import com.rockcent.common.domain.enumclass.Whether;
import com.rockcent.common.utils.HttpClientUtils;
import com.rockcent.mall.lib.domain.Customer;
import com.rockcent.mall.lib.domain.CustomerFund;
import com.rockcent.mall.lib.domain.Mall;
import com.rockcent.mall.lib.domain.MiniAppConfig;
import com.rockcent.mall.lib.domain.enumclass.WechatMessageCode;
import com.rockcent.mall.lib.dto.CustomerDto;
import com.rockcent.mall.lib.dto.WxAppUserDto;
import com.rockcent.mall.lib.repository.CustomerFundRepository;
import com.rockcent.mall.lib.repository.CustomerRepository;
import com.rockcent.mall.lib.repository.MallRepository;
import com.rockcent.mall.lib.repository.MiniAppConfigRepository;
import com.rockcent.wechat.Routes;
import com.rockcent.wechat.helper.CustomerHelper;
import com.rockcent.wechat.helper.WechatHelper;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by HK on 16/10/11.
 */
@RestController
@RequestMapping(value = Routes.API_PREFIX)
public class WechatController extends BaseController {

    private final Logger log = LoggerFactory.getLogger(WechatController.class);
    @Autowired
    private WechatHelper wechatHelper;
    @Autowired
    private CustomerRepository customerRepository;
    @Autowired
    private MallRepository mallRepository;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private CustomerHelper customerHelper;
    @Autowired
    private CustomerFundRepository customerFundRepository;

    @Autowired
    private MiniAppConfigRepository miniAppConfigRepository;
    /**
     * @api {get} /api/v2/wechat/auth 微信 用户认证
     * @apiGroup wechat
     * @apiVersion 1.0.0
     * @apiParam {String} code 微信认证 code
     * @apiParam {String} state 微信认证 state
     * @apiParam {String} domain 微信认证 域名参数
     * @apiParam {String} backUrl 微信认证 成功后返回的url
     * @apiExample {微信oauth2 请求方式}  例如:
     * https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxce62f97f15d07734&redirect_uri=http%3A%2F%2Fbeta.c.uat.rockcent.com%2Fapi%2Fv2%2Fwechat%2Fauth%3Fdomain%3Dbeta.c.uat.rockcent.com&response_type=code&scope=snsapi_base&state=001#wechat_redirect
     */
    @RequestMapping(value = Routes.WECHAT_AUTH, method = RequestMethod.GET)
    public void auth(String code, String state, String domain, String backUrl, Model model, HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) throws IOException {
        WebDoing1 doing = (req, mod, viewData) -> {
            if (StringUtils.isBlank(code)) {
                log.warn("======================>code 不能为空",log);
                return;
            }

            if (StringUtils.isBlank(domain)) {
                log.warn("======================>domain 不能为空",log);
                return;
            }

            Mall mall = mallRepository.findByMobileHostName(domain);
            if (mall == null) {
                log.warn("======================>{} 对应的 mall 不存在", domain);
                return;
            }

            WxMpService wxMpService = wechatHelper.getWxMpService(domain);
            WxMpOAuth2AccessToken wxMpOAuth2AccessToken;
            WxMpUser wxMpUser;
            try {
                wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
                wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, "zh_CN");
//                log.info("======================>wechat auth openId  {}", wxMpOAuth2AccessToken.getOpenId());
            } catch (WxErrorException e) {
//                log.warn(e.getMessage());
                log.error("======================>code 无效",e);
                return;
            }
            if (wxMpOAuth2AccessToken == null) {
                log.warn("======================>code 无效");
                return;
            }
            log.info(wxMpOAuth2AccessToken.toString());
            String openId = wxMpOAuth2AccessToken.getOpenId();
            String unionId = wxMpOAuth2AccessToken.getUnionId();
            Customer customer = customerRepository.findByWechatOpenId(openId);
            if (customer == null) { // 证明用户是首次使用
                customer = new Customer();
                if (wxMpUser != null) {
                    customer.setNickName(wxMpUser.getNickname());
                    customer.setWechatHeadimgurl(wxMpUser.getHeadImgUrl());
                    customer.setWechatNickName(wxMpUser.getNickname());
                }
                customer.setMallId(mall.getId());
                customer.setWechatOpenId(openId);
                customer.setWechatUnionId(unionId);
                customer.setShareCode(customerHelper.genShareCode());
                customer = customerRepository.save(customer);
            }else{
                String wechatUnionId = customer.getWechatUnionId();
                if(StringUtils.isBlank(wechatUnionId)){
                    customer.setWechatUnionId(unionId);
                }
                customerRepository.save(customer);
            }

            // 添加用户钱包信息
            CustomerFund customerFund = customerFundRepository.findByCustomerIdAndIsDelete(customer.getId(), Whether.NO);
            if (customerFund == null) {
                customerFund = new CustomerFund();
                customerFund.setCustomerId(customer.getId());
                //络享体验平台 给用户默认加一万块金额
                if (Objects.equals(customer.getMallId(), 2L)) {
                    customerFund.setAvailableAmount(BigDecimal.valueOf(10000));
                    customerFund.setTotalAmount(BigDecimal.valueOf(10000));
                }
                customerFund = customerFundRepository.save(customerFund);
                customer.setCustomerFundId(customerFund.getId());
                customerRepository.save(customer);
            }

            // 包装用户信息
            customerHelper.setSession(customer, request, response);

            String redirectUrl = String.format("http://%s/", domain);
            if (StringUtils.isNotBlank(backUrl)) {
                redirectUrl = backUrl;
            }
            // 跳转页面
//            viewData.redirect(redirectUrl);
            viewData.view = redirectUrl;
        };
        String view = doing.go(request, model, redirectAttributes, log);
        response.sendRedirect(view);

    }

    /**
     * @api {get} /api/v2/wechat/auth_simulation 微信 用户模拟认证
     * @apiGroup wechat
     * @apiVersion 1.0.0
     * @apiParam {String} customerId <code>必须参数</code>用户id
     * @apiExample {模拟微信oauth2 请求方式}  例如:
     * 打开浏览器输入 : http://api.wechat.uat.rockcent.com/api/v2/wechat/auth_simulation?customerId=?
     */
    @RequestMapping(value = "/wechat/auth_simulation", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult authSimulation(Long customerId, HttpServletRequest request, HttpServletResponse response) {
        RestDoing doing = jsonResult -> {
            Customer customer = customerRepository.findOne(customerId);

            // 添加用户钱包信息
            CustomerFund customerFund = customerFundRepository.findByCustomerIdAndIsDelete(customer.getId(), Whether.NO);
            if (customerFund == null) {
                customerFund = new CustomerFund();
                customerFund.setCustomerId(customer.getId());
                customerFundRepository.save(customerFund);
            }
            customerHelper.setSession(customer, request, response);
            jsonResult.data = customerHelper.getSession(request).getUserToken();
        };
        return doing.go(request, log);
    }

    /**
     * @api {post} /api/v2/wechat/config 微信 公众号对接
     * @apiVersion 1.0.0
     * @apiGroup wechat
     */
    @RequestMapping(value = Routes.WECHAT_CONFIG, method = {RequestMethod.POST, RequestMethod.GET})
    public void config(HttpServletRequest request, HttpServletResponse response, String signature, String timestamp, String nonce, String echostr) {
        String domain = request.getParameter("domain");
        Enumeration<String> parameterNames = request.getParameterNames();
        StringBuffer parameterStringBuffer = new StringBuffer("params => { ");
        while (parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            parameterStringBuffer.append(parameterName).append(" : ").append(request.getParameter(parameterName)).append(" ,");
        }
        parameterStringBuffer.deleteCharAt(parameterStringBuffer.length() - 1);
        parameterStringBuffer.append(" } ");
        log.info(parameterStringBuffer.toString());

        WxMpService wxMpService = wechatHelper.getWxMpService(domain);

        try {
            Mall mall = mallRepository.findByMobileHostName(domain);
            if(mall==null) {
                response.getWriter().println("非法的domain");
                response.getWriter().close();
            }
            // 事件处理 end
            if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
                // 消息签名不正确，说明不是公众平台发过来的消息
                response.getWriter().println("非法请求");
                response.getWriter().close();
                return;
            }
            if (StringUtils.isNotBlank(echostr)) {
                // 说明是一个仅仅用来验证的请求，回显echostr
                response.getWriter().println(echostr);
                response.getWriter().close();
                return;
            }
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream());
//            log.info("inMessage : {}", inMessage);
            log.info("accessToken : {}", wxMpService.getAccessToken());
            String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type")) ? "raw" : request.getParameter("encrypt_type");
            if ("raw".equals(encryptType)) {
                // 明文传输的消息
                //回复消息
                sendMsg(wxMpService,inMessage,mall.getId(),response);
                return;
            }
            response.getWriter().println("不可识别的加密类型");
            response.getWriter().close();
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            log.error(e.getMessage());
            StackTraceElement[] stackTraceElements = e.getStackTrace();
            for (int i = 0; i < stackTraceElements.length; i++) {
                StackTraceElement stackTraceElement = stackTraceElements[i];
                log.error(stackTraceElement.toString());
            }
        }
    }

    private void sendMsg(WxMpService wxMpService, WxMpXmlMessage inputMessage, Long mallId, HttpServletResponse response) throws Exception {
        if(inputMessage==null) {
            return;
        }
        String msgType = inputMessage.getMsgType();
        String event = inputMessage.getEvent();
        String content = inputMessage.getContent();
        if(StringUtils.isEmpty(msgType)) {
            return;
        }
        List<String> msgs = new ArrayList<>();
        if("event".equals(msgType)) {
            if(StringUtils.isNotEmpty(event) && "subscribe".equals(event)) {
                String retMsg = wechatHelper.subscribeAndReplyMsg(WechatMessageCode.ADD_FRIEND_REPLY.toString(),inputMessage.getToUser(),inputMessage.getFromUser(),mallId);
                if(StringUtils.isNotEmpty(retMsg)) {
                    msgs.add(retMsg);
                }
            }
        } else if ("text".equals(msgType) || "image".equals(msgType)|| "video".equals(msgType) || "voice".equals(msgType) || "news".equals(msgType)) {
            List<String> keywordMsgs = null;
            if(StringUtils.isNotEmpty(content)) {
                keywordMsgs = wechatHelper.keywordReplyMsg(inputMessage.getToUser(), inputMessage.getFromUser(), mallId, content);
            }
            if(keywordMsgs==null || keywordMsgs.size()==0) {
                String retMsg = wechatHelper.subscribeAndReplyMsg(WechatMessageCode.ADD_FRIEND_AUTOREPLY.toString(), inputMessage.getToUser(), inputMessage.getFromUser(), mallId);
                if (StringUtils.isNotEmpty(retMsg)) {
                    msgs.add(retMsg);
                }
            } else {
//                log.info("-------------------keywordMsgs num:{}",keywordMsgs.size());
                if(keywordMsgs.size()>1) {
                    String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
                    for(String msg:keywordMsgs) {
//                        log.info("sendContent:{}",msg);
                        String responseContent = wxMpService.post(url, msg);
//                        log.info("responseContent:{}",responseContent);
                    }
                } else {
                    msgs.addAll(keywordMsgs);
                }
            }
        }
//        log.info("-------------------msg num:{}",msgs.size());
        if(msgs!=null && msgs.size()==1) {
            for(String msg:msgs) {
//                log.info("-------------msg content:{}",msg);
                response.getWriter().write(msg);
            }
            response.getWriter().close();
        }
    }

    private void all(WxMpMessageRouter wxMpMessageRouter) {


        // 事件处理 start
        wxMpMessageRouter
                .rule()
                .async(false)
                .rContent(".*")
                .handler((WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) -> {
                    String openid = wxMessage.getFromUser();
//                    WxMpUser user = wxMpService.oauth2getUserInfo().userInfo(openid, "zh_CN");
//                    log.info("======================>user : {}", user.toString());
//                    log.info("======================>wxMessage..getToUser()  {}", wxMessage.getToUser());
//                    log.info("======================>wxMessage..getFromUser() :{}", wxMessage.getFromUser());
                    WxMpXmlOutTextMessage m = WxMpXmlOutMessage
                            .TEXT()
                            .content("您好!")
                            .fromUser(wxMessage.getToUser())
                            .toUser(wxMessage.getFromUser())
                            .build();
                    return m;
                }).end();
    }

    /**
     * @api {get} /api/v2/wechat/jssdk/config 微信 jssdk.config 参数获取
     * @apiGroup wechat
     * @apiVersion 1.0.0
     * @apiHeader {String} userToken <code>必须参数</code> 用户token
     * @apiHeader {String} domain <code>必须参数</code>请求域名
     * @apiParam {String} url <code>必须参数</code>当前请求url
     * @apiSuccess {String} APPID
     * @apiSuccess {String} noncestr
     * @apiSuccess {Long} timestamp
     * @apiSuccess {String} url
     * @apiSuccess {String} signature
     * @apiSuccessExample {json} Response
     * {
     * "code" : 1,
     * "desc" : "",
     * "data" : {
     * "appid" : "qrgfd4g2g2g",
     * "noncestr" : "sdfgregdsf",
     * "timestamp" : 234234562342342343242,
     * "url" : "beta.c.uat.rockcent.com",
     * "signature" : "sdjfsn24rsdnsionsi43nfdk"
     * }
     * }
     */
    @RequestMapping(value = Routes.WECHAT_JSSDK_CONFIG, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult jssdkConfig(String url, HttpServletRequest request) {
        CustomerDto customerDto = customerHelper.getSession(request);
        RestDoing doing = jsonResult -> {

            if (StringUtils.isBlank(url)) {
                jsonResult.errorParam("url 不能为空",log);
                return;
            }

            WxMpService wxMpService = wechatHelper.getWxMpService(customerDto.getMallCustomerDomain());
            WxJsapiSignature wxJsapiSignature = wxMpService.createJsapiSignature(url);
            jsonResult.data = wxJsapiSignature;
        };
        return doing.go(request, objectMapper, log);
    }

    /**
     * @api {post} /api/v2/wxapp/auth 微信小程序 用户认证
     * @apiGroup wechat
     * @apiVersion 1.0.0
     * @apiParam {String} code 微信认证 code
     * @apiParam {String} state 微信认证 state
     * @apiParam {String} domain 微信认证 域名参数
     * @apiExample {json}  例如:
     * {
     * <p>
     * }
     */
    @RequestMapping(value = Routes.WXAPP_AUTH, method = RequestMethod.POST)
    public JsonResult wxapp_auth(@RequestBody WxAppUserDto wxAppUserDto, HttpServletRequest request, HttpServletResponse response) throws IOException {
        RestDoing doing = jsonResult -> {
            if (StringUtils.isBlank(wxAppUserDto.getCode())) {
                log.warn("======================>code 不能为空",log);
                return;
            }

            if (StringUtils.isBlank(wxAppUserDto.getDomain())) {
                log.warn("======================>domain 不能为空",log);
                return;
            }

            Mall mall = mallRepository.findByMobileHostName(wxAppUserDto.getDomain());
            if (mall == null) {
                log.warn("======================>{} 对应的 mall 不存在", wxAppUserDto.getDomain());
                return;
            }
            MiniAppConfig miniAppConfig = miniAppConfigRepository.findByMallId(mall.getId());
            if (miniAppConfig == null) {
                return;
            }

            String wxapp_api= miniAppConfig.getAppId();
            String wxapp_appsecret = miniAppConfig.getAppSecret();
            StringBuilder url = new StringBuilder();
            url.append("https://api.weixin.qq.com/sns/jscode2session?");
            url.append("appid=").append(wxapp_api);
            url.append("&secret=").append(wxapp_appsecret);
            url.append("&js_code=").append(wxAppUserDto.getCode());
            url.append("&grant_type=authorization_code");

            //log.warn(url.toString());

            String result = null;
            result = HttpClientUtils.SINGLETON.sendGet(url.toString());
//            log.info("======================>result:" + result);
            Map mapTypes = JSON.parseObject(result);
            WxMpUser wxMpUser = new WxMpUser();
            wxMpUser.setNickname(wxAppUserDto.getNickName());
            wxMpUser.setCity(wxAppUserDto.getCity());
            wxMpUser.setProvince(wxAppUserDto.getProvince());
            wxMpUser.setCountry(wxAppUserDto.getCountry());
            wxMpUser.setHeadImgUrl(wxAppUserDto.getAvatarUrl());
            String openId = (String) mapTypes.get("openid");
            String session_key = (String) mapTypes.get("session_key");

            //log.warn("" + mapTypes);

            //log.warn("OPEN_ID: " + openId);
            //log.warn("session_key: " + session_key);
   
            Customer customer = createCustomerAccount(mall, wxMpUser, openId);

            //log.warn("CUSTOMER ID: " + customer.getId());
            //log.warn("customer mall id: " + customer.getMallId());


            // 添加用户钱包信息
            CustomerFund customerFund = customerFundRepository.findByCustomerIdAndIsDelete(customer.getId(), Whether.NO);
            if (customerFund == null) {
                customerFund = new CustomerFund();
                customerFund.setCustomerId(customer.getId());

//                customerFundRepository.save(customerFund);
                customerFund = customerFundRepository.save(customerFund);
                customer.setCustomerFundId(customerFund.getId());
                customerRepository.save(customer);
            }
            //
            CustomerDto customerDto = customerHelper.setSession(customer, request, response);

            Map<String, String> data = new HashMap<>();
            String sessionId = customerDto.getUserToken();
            data.put("sessionId", sessionId);
            data.put("mobile", customerDto.getMobile());
            jsonResult.data = data;
        };
        return doing.go(request, objectMapper, log);
    }

    /**
     * 创建账户信息
     *
     * @param mall     平台信息
     * @param wxMpUser 微信返回信息
     * @param openId   平台信息
     * @return
     */
    private Customer createCustomerAccount(Mall mall, WxMpUser wxMpUser, String openId) {
        Customer customer = customerRepository.findTop1ByWxappOpenIdAndIsDelete(openId,Whether.NO);
        if (customer == null) { // 用户是第一次登陆，创建用户账号
            customer = new Customer();
            if (wxMpUser != null) {
                customer.setNickName(wxMpUser.getNickname());
                customer.setWechatHeadimgurl(wxMpUser.getHeadImgUrl());
                customer.setWechatNickName(wxMpUser.getNickname());
                customer.setCity(wxMpUser.getCity());
                customer.setCountry(wxMpUser.getCountry());
                customer.setProvince(wxMpUser.getProvince());
            }
            customer.setMallId(mall.getId());
            customer.setWxappOpenId(openId);
            customer.setShareCode(customerHelper.genShareCode());
            customer = customerRepository.save(customer);
        }
        return customer;
    }

    /**
     * @api {get} /check/login 检查登录状态
     * @apiSuccessExample {json} Success-Response:
     * {
     *  "code": "1",
     *  "desc": "成功"
     * }
     *
     */
    @RequestMapping(value = Routes.CHECK_LOGIN, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult chcekLogin(HttpServletRequest request) {
        RestDoing doing = jsonResult -> {
        };
        return doing.go(request, objectMapper, log);
    }




}
